package com.siashan.sensitive.serializer;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.siashan.sensitive.AbstractDesensitization;
import com.siashan.sensitive.Sensitive;
import com.siashan.sensitive.SensitiveException;
import com.siashan.sensitive.serializer.AbstractSensitiveStrategy;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.io.IOException;
import java.util.Objects;

/**
 * 敏感信息序列化时 过滤
 *
 * @author siashan
 * @date 2023/4/3
 * @since 1.2.1
 */
public class SensitiveJsonSerializer extends JsonSerializer<String>
        implements ContextualSerializer, ApplicationContextAware {
    private Class<? extends AbstractSensitiveStrategy> strategy;

    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        // 字段序列化处理
        try {
            gen.writeString(strategy.newInstance().serialize(value));
        } catch (Exception e) {
            throw new SensitiveException("敏感词序列化异常！",e);
        }
    }

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {

        //获取敏感枚举
        Sensitive annotation = property.getAnnotation(Sensitive.class);

        if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass())) {

            Class<? extends AbstractDesensitization> desensitizationClazz = annotation.desensitization();
            try {
                AbstractDesensitization abstractDesensitization = desensitizationClazz.newInstance();
                boolean desensitization = abstractDesensitization.desensitization();
                if (desensitization) {
                    //如果有敏感注解，则加入脱敏规则
                    this.strategy = annotation.strategy();
                    return this;
                }

            } catch (Exception e) {
                throw new SensitiveException("敏感词序列化异常！",e);
            }
        }
        return prov.findValueSerializer(property.getType(), property);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    }
}
